<!DOCTYPE html>
<html>

<head>

<meta charset="utf-8">
<title>Ares开发指南</title>


<style type="text/css">
*{margin:0;padding:0;}
body {
	font:13.34px helvetica,arial,freesans,clean,sans-serif;
	color:black;
	line-height:1.4em;
	background-color: #F8F8F8;
	padding: 0.7em;
}
p {
	margin:1em 0;
	line-height:1.5em;
}
table {
	font-size:inherit;
	font:100%;
	margin:1em;
}
table th{border-bottom:1px solid #bbb;padding:.2em 1em;}
table td{border-bottom:1px solid #ddd;padding:.2em 1em;}
input[type=text],input[type=password],input[type=image],textarea{font:99% helvetica,arial,freesans,sans-serif;}
select,option{padding:0 .25em;}
optgroup{margin-top:.5em;}
pre,code{font:12px Monaco,"Courier New","DejaVu Sans Mono","Bitstream Vera Sans Mono",monospace;}
pre {
	margin:1em 0;
	font-size:12px;
	background-color:#eee;
	border:1px solid #ddd;
	padding:5px;
	line-height:1.5em;
	color:#444;
	overflow:auto;
	-webkit-box-shadow:rgba(0,0,0,0.07) 0 1px 2px inset;
	-webkit-border-radius:3px;
	-moz-border-radius:3px;border-radius:3px;
}
pre code {
	padding:0;
	font-size:12px;
	background-color:#eee;
	border:none;
}
code {
	font-size:12px;
	background-color:#f8f8ff;
	color:#444;
	padding:0 .2em;
	border:1px solid #dedede;
}
img{border:0;max-width:100%;}
abbr{border-bottom:none;}
a{color:#4183c4;text-decoration:none;}
a:hover{text-decoration:underline;}
a code,a:link code,a:visited code{color:#4183c4;}
h2,h3{margin:1em 0;}
h1,h2,h3,h4,h5,h6{border:0;}
h1{font-size:170%;border-top:4px solid #aaa;padding-top:.5em;margin-top:1.5em;}
h1:first-child{margin-top:0;padding-top:.25em;border-top:none;}
h2{font-size:150%;margin-top:1.5em;border-top:4px solid #e0e0e0;padding-top:.5em;}
h3{margin-top:1em;}
hr{border:1px solid #ddd;}
ul{margin:1em 0 1em 2em;}
ol{margin:1em 0 1em 2em;}
ul li,ol li{margin-top:.5em;margin-bottom:.5em;}
ul ul,ul ol,ol ol,ol ul{margin-top:0;margin-bottom:0;}
blockquote{margin:1em 0;border-left:5px solid #ddd;padding-left:.6em;color:#555;}
dt{font-weight:bold;margin-left:1em;}
dd{margin-left:2em;margin-bottom:1em;}
sup {
    font-size: 0.83em;
    vertical-align: super;
    line-height: 0;
}
kbd {
  display: inline-block;padding: 3px 5px;font-size: 11px;line-height: 10px;color: #555;vertical-align: middle;background-color: #fcfcfc;border: solid 1px #ccc;border-bottom-color: #bbb;border-radius: 3px;box-shadow: inset 0 -1px 0 #bbb;
}
* {
	-webkit-print-color-adjust: exact;
}
@media screen and (min-width: 914px) {
    body {
        width: 854px;
        margin:0 auto;
    }
}
@media print {
	table, pre {
		page-break-inside: avoid;
	}
	pre {
		word-wrap: break-word;
	}
}
</style>

<style type="text/css">
/**
 * prism.js default theme for JavaScript, CSS and HTML
 * Based on dabblet (http://dabblet.com)
 * @author Lea Verou
 */

code[class*="language-"],
pre[class*="language-"] {
	color: black;
	background: none;
	text-shadow: 0 1px white;
	font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
	text-align: left;
	white-space: pre;
	word-spacing: normal;
	word-break: normal;
	word-wrap: normal;
	line-height: 1.5;

	-moz-tab-size: 4;
	-o-tab-size: 4;
	tab-size: 4;

	-webkit-hyphens: none;
	-moz-hyphens: none;
	-ms-hyphens: none;
	hyphens: none;
}

pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
	text-shadow: none;
	background: #b3d4fc;
}

pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
code[class*="language-"]::selection, code[class*="language-"] ::selection {
	text-shadow: none;
	background: #b3d4fc;
}

@media print {
	code[class*="language-"],
	pre[class*="language-"] {
		text-shadow: none;
	}
}

/* Code blocks */
pre[class*="language-"] {
	padding: 1em;
	margin: .5em 0;
	overflow: auto;
}

:not(pre) > code[class*="language-"],
pre[class*="language-"] {
	background: #f5f2f0;
}

/* Inline code */
:not(pre) > code[class*="language-"] {
	padding: .1em;
	border-radius: .3em;
	white-space: normal;
}

.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
	color: slategray;
}

.token.punctuation {
	color: #999;
}

.namespace {
	opacity: .7;
}

.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
	color: #905;
}

.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
	color: #690;
}

.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
	color: #a67f59;
	background: hsla(0, 0%, 100%, .5);
}

.token.atrule,
.token.attr-value,
.token.keyword {
	color: #07a;
}

.token.function {
	color: #DD4A68;
}

.token.regex,
.token.important,
.token.variable {
	color: #e90;
}

.token.important,
.token.bold {
	font-weight: bold;
}
.token.italic {
	font-style: italic;
}

.token.entity {
	cursor: help;
}
</style>


</head>

<body>

<h2 id="toc_0">Ares项目开发指南</h2>

<ul>
<li>开发环境搭建</li>
<li>框架初始化</li>
<li>配置文件</li>
<li>构建数据库SQL</li>
<li>用户登录</li>
<li>Gii快速生成项目</li>
<li>Model编写</li>
<li>Controller编写</li>
<li>Template编写</li>
<li>项目自测</li>
<li>测试环境测试</li>
<li>项目提交发布环境</li>
</ul>

<p>以下我们以建一个<code>test</code>项目为例</p>

<ul>
<li>项目名称：<code>test</code></li>
<li>项目根目录: <code>D:/wamp/www/test</code></li>
<li>虚拟主机访问地址:<code>http://test.com</code></li>
<li>主要功能:

<ul>
<li>用户登录注册</li>
<li>权限控制</li>
<li>文章管理功能</li>
<li>编写一个图片上传功能</li>
<li>为发布文章增加验证码
#####开发环境搭建</li>
</ul></li>
<li><p>配置虚拟主机</p>

<p><VirtualHost *:80>
    ServerAdmin webmaster@dummy-host2.example.com
    DocumentRoot &quot;D:/project_zyb/main&quot;
    ServerName zhiyebao
    ErrorLog &quot;logs/dummy-host2.ares-error.log&quot;
    CustomLog &quot;logs/dummy-host2.ares-access.log&quot; common
</VirtualHost></p></li>
<li><p>修改hosts Widows <code>C:\Windows\System32\drivers\etc</code> Linux: <code>/etc/hosts</code></p>

<ul>
<li>添加以下内容：<code>127.0.0.1 test.com</code></li>
</ul></li>
<li><p>在<code>D:/wamp/www/test</code>建立文件<code>info.php</code>，内容如下：</p>

<p>&lt;?php
phpinfo();
?&gt;</p></li>
</ul>

<ol>
<li><p>访问<code>http://test.com/info.php</code>,测试效果。</p>

<h5 id="toc_1">框架初始化</h5>

<p>框架<code>svn</code>地址<code>svn://xxxxxxxx:xxxx/ares_wiki/backend/yii_ares_kickoff</code></p></li>
</ol>

<ul>
<li>从svn导出代码（<code>右键yii_ares_kickoff-&gt;TortoiseSvn-&gt;export</code>） 包括 <code>framework</code> 和 <code>main</code>到<code>D:/wamp/www/test</code>目录</li>
<li><p>目录文件结构及说明</p>

<ul>
<li>framework <code>框架目录</code></li>
<li><p>main <code>项目目录</code></p>

<ul>
<li><p>protected <code>应用目录</code></p>

<ul>
<li>admin <code>后台程序目录,对应http://test.com/admin.php</code>

<ul>
<li>components <code>存放admin.php控制器基类Controller.php 用户登录验证等文件</code> </li>
<li>controllers <code>存放admin.php 所访问的控制器</code></li>
<li>models <code>存放admin.php独有的数据模型文件</code></li>
<li>themes <code>存放admin.php所对应的模板目录</code></li>
</ul></li>
<li>components <code>组件目录,存放index.php控制器基类Controller.php 用户登录验证等文件</code></li>
<li>config <code>存放应用程序的配置文件 main.php</code></li>
<li>controllers <code>存放index.php所访问的控制器</code></li>
<li>extensions <code>存放应用程序的扩展,如：smarty/文件上传/图片处理/邮件服务等扩展</code></li>
<li>models <code>存放前后台共用的数据模型</code></li>
<li>modules <code>存放应用程序的模块，该目录可以用来构建应用程序的子系统</code></li>
<li>themes <code>index.php所对应的模板文件存放目录</code></li>
<li>vendor </li>
</ul></li>
<li><p>resource <code>资源目录 包括Css、Js、Image等</code></p></li>
<li><p>upload <code>上传目录</code></p></li>
<li><p>admin.php <code>后台入口文件</code></p></li>
<li><p>index.php <code>前台入口文件</code></p>

<h5 id="toc_2">配置文件</h5>

<p>配置文件：<code>D:/wamp/www/test/protected/main.php</code> </p></li>
</ul></li>
</ul></li>
</ul>

<p>说明：<code>用于配置应用程序的基本信息</code></p>

<div><pre><code class="language-none">&lt;?php
//下面是分离前后台需要增加的   
$backend = dirname(dirname(__FILE__));//指定后台的目录
$frontend = dirname($backend);//应用程序的根目录
Yii::setPathOfAlias(&#39;backend&#39;, $backend);//设置别名
//application.path = /main/protected/path application 对应的目录是/main/protected
$arrConfig = array(
    &#39;language&#39; =&gt; &#39;zh_CN&#39;,//指定程序的语言
    &#39;basePath&#39; =&gt; $frontend,//程序的根目录
    &#39;controllerPath&#39; =&gt; $backend . &#39;/controllers&#39;,//控制器所在的目录，后台分离为 /main/protected/admin/controllers
    &#39;name&#39; =&gt; &#39;Ares Kickoff Application&#39;,
    // preloading &#39;log&#39; component
    &#39;preload&#39; =&gt; array(&#39;log&#39;),
    &#39;defaultController&#39; =&gt; &#39;Index&#39;,//默认的控制器
    // autoloading model and component classes
    &#39;import&#39; =&gt; array(
        //model一部分使用公共的
        &#39;application.models.*&#39;,
        //controllers components使用私有的 model 部分私有
        &#39;backend.controllers&#39;,
        &#39;backend.models.*&#39;,
        &#39;backend.components.*&#39;,
        //扩展使用共有
        &#39;application.vendor.Smarty.sysplugins.*&#39;,
        &#39;application.extensions.*&#39;,
    ),
    &#39;modules&#39; =&gt; array(
        // Gii配置
        &#39;gii&#39; =&gt; array(
            &#39;class&#39; =&gt; &#39;system.gii.GiiModule&#39;,
            &#39;password&#39; =&gt; &#39;123456&#39;,//gii访问密码
            // 默认只允许本机访问 Gii,考虑到安全性，不应在测试及线上环境开放Gii。
            &#39;ipFilters&#39; =&gt; array(&#39;127.0.0.1&#39;, &#39;::1&#39;),
        ),
    ),
    // application components
    &#39;components&#39; =&gt; array(
        &#39;admin&#39; =&gt; array(//后台用户身份管理类 Yii::app()-&gt;admin
            // enable cookie-based authentication
            &#39;class&#39; =&gt; &#39;AdminWebUser&#39;, /main/protected/admin/compents/AdminWebUser.php
            &#39;stateKeyPrefix&#39; =&gt; &#39;admin&#39;,//SESSION前缀，用来区分前后台用户登录信息
            &#39;allowAutoLogin&#39; =&gt; true,
        ),
        // URL的访问模式管理,打开注释后Yii访问采用Path模式
        /*
          &#39;urlManager&#39;=&gt;array(
              &#39;urlFormat&#39;=&gt;&#39;path&#39;,
              &#39;rules&#39;=&gt;array(
                  &#39;&lt;controller:\w+&gt;/&lt;id:\d+&gt;&#39;=&gt;&#39;&lt;controller&gt;/view&#39;,
                  &#39;&lt;controller:\w+&gt;/&lt;action:\w+&gt;/&lt;id:\d+&gt;&#39;=&gt;&#39;&lt;controller&gt;/&lt;action&gt;&#39;,
                  &#39;&lt;controller:\w+&gt;/&lt;action:\w+&gt;&#39;=&gt;&#39;&lt;controller&gt;/&lt;action&gt;&#39;,
                  ),
          ),
         */
        //引入Smarty
        &#39;smarty&#39; =&gt; array(
            &#39;class&#39; =&gt; &#39;application.extensions.CSmarty&#39;,
        ),
        // 数据库访问
        &#39;db&#39; =&gt; array(
            &#39;connectionString&#39; =&gt; &#39;mysql:host=xxxxxxxx;dbname=xxxxxxxx&#39;,
            &#39;emulatePrepare&#39; =&gt; true,
            &#39;username&#39; =&gt; &#39;xxxxxxxx&#39;,
            &#39;password&#39; =&gt; &#39;xxxxxxxx&#39;,
            &#39;charset&#39; =&gt; &#39;utf8&#39;,
        ),
         */
        &#39;errorHandler&#39; =&gt; array(
            // 使用site/error来显示错误页面
            &#39;errorAction&#39; =&gt; &#39;site/error&#39;,
        ),
        //log开启配置
        &#39;log&#39; =&gt; array(
            &#39;class&#39; =&gt; &#39;CLogRouter&#39;,
            &#39;routes&#39; =&gt; array(
                array(
                    &#39;class&#39; =&gt; &#39;CFileLogRoute&#39;,
                    &#39;levels&#39; =&gt; &#39;error, warning&#39;,
                ),
            ),
        ),
    ),
    // 程序用到的公共参数
    // using Yii::app()-&gt;params[&#39;paramName&#39;]
    &#39;params&#39; =&gt; array(
        &#39;authDebug&#39; =&gt; false,
        &#39;adminEmail&#39; =&gt; &#39;webmaster@example.com&#39;,
        //template
        &#39;frontendTplDir&#39; =&gt; &#39;tpl&#39;,
        &#39;backendTplDir&#39; =&gt; &#39;tpl&#39;,
        &#39;pageSize&#39; =&gt; 10,
        &#39;resourcePath&#39; =&gt; &#39;resource/thirdvendor/aceadmin1.3.1&#39;,
        &#39;resourceBasePath&#39; =&gt; &#39;resource/thirdvendor&#39;,
        &#39;uploadPic&#39; =&gt; array(
           &#39;basePath&#39; =&gt; dirname(__FILE__) . DIRECTORY_SEPARATOR . &#39;..&#39; . DIRECTORY_SEPARATOR . &quot;..&quot; . DIRECTORY_SEPARATOR . &quot;upload&quot;,
        ),
        &#39;tplPath&#39; =&gt; &quot;/admin&quot;,
        //this is userd for LOG CONFIG
        &#39;LOG_PATH&#39; =&gt; &#39;/var/log/www/ares_admin/&#39;,
        &#39;LOG_NAME&#39; =&gt; &#39;ares_admin.log&#39;,
        //&#39;LOG_LEVEL&#39;=&gt;&#39;&#39;,
        //&#39;LOG_MAIL&#39;=&gt;&#39;&#39;,
        //属性ID
    ),
);

// 加入其他配置
if (!empty($_GET[&#39;debug&#39;]) &amp;&amp; strtolower(trim($_GET[&#39;debug&#39;])) == &#39;true&#39;) {
        $arrConfig[&#39;components&#39;][&#39;log&#39;][&#39;routes&#39;][] = array(
            &#39;class&#39; =&gt; &#39;ext.yiidebugtb.XWebDebugRouter&#39;,
            &#39;config&#39; =&gt; &#39;alignLeft, opaque, runInDebug, fixedPos, collapsed, yamlStyle&#39;,
            &#39;levels&#39; =&gt; &#39;error, warning, trace, profile, info&#39;,
            &#39;allowedIPs&#39; =&gt; array(&#39;127.0.0.1&#39;, &#39;::1&#39;, &#39;192.168.1.54&#39;, &#39;192\.168\.1[0-5]\.[0-9]{3}&#39;),
        );
}

return $arrConfig;</code></pre></div>

<h5 id="toc_3">用户登录</h5>

<p>yii提供了CUserIdentity类,这个类一般用于验证用户名和密码的类.</p>

<p>继承后我们需要重写其中的authenticate()方法来实现我们自己的验证方法.具体代码如下:</p>

<div><pre><code class="language-none">class UserIdentity extends CUserIdentity { 
    private $_id; 
    public function authenticate() { 
        $record=User::model()-&gt;findByAttributes(array(&#39;username&#39;=&gt;$this-&gt;username)); 
        if($record===null) 
            $this-&gt;errorCode=self::ERROR_USERNAME_INVALID; 
        else if($record-&gt;password!==md5($this-&gt;password)) 
            $this-&gt;errorCode=self::ERROR_PASSWORD_INVALID; 
        else { 
            $this-&gt;_id=$record-&gt;id; 
            $this-&gt;setState(&#39;title&#39;, $record-&gt;title); 
            $this-&gt;errorCode=self::ERROR_NONE; 
        } 
        return !$this-&gt;errorCode; 
    } 

    public function getId() { 
        return $this-&gt;_id; 
    } 
}</code></pre></div>

<p>在用户登陆时则调用如下代码:</p>

<div><pre><code class="language-none">$identity=new UserIdentity($username,$password);
if($identity-&gt;authenticate()) 
    Yii::app()-&gt;user-&gt;login($identity); 
else 
    echo $identity-&gt;errorMessage;</code></pre></div>

<p>在用户退出是调用了<code>Yii::app()-&gt;user-&gt;logout();</code></p>

<p>CWebuser记录session的值</p>

<p>在验证用户名和密码成功后yii调用cwebuser的login方法</p>

<div><pre><code class="language-none">login($identity,$duration=0){
    $id=$identity-&gt;getId();
    $states=$identity-&gt;getPersistentStates();
    if($this-&gt;beforeLogin($id,$states,false)){
        $this-&gt;changeIdentity($id,$identity-&gt;getName(),$states);

        if($duration&gt;0){
            if($this-&gt;allowAutoLogin)
                $this-&gt;saveToCookie($duration);
            else
                throw new CException(Yii::t(&#39;yii&#39;,&#39;{class}.allowAutoLogin must be set true in order to use cookie-based authentication.&#39;,array(&#39;{class}&#39;=&gt;get_class($this))));
        }

        $this-&gt;afterLogin(false);
    }
}</code></pre></div>

<p>在changeIdentity方法中调用了：</p>

<div><pre><code class="language-none">$this-&gt;setId($id);
$this-&gt;setName($name);
//分别将__id和__name保存到session中
public function setState($key,$value,$defaultValue=null){
    $key=$this-&gt;getStateKeyPrefix().$key;//获取app的编号
    if($value===$defaultValue)
        unset($_SESSION[$key]);
    else
        $_SESSION[$key]=$value;
}
$this-&gt;loadIdentityStates($states);</code></pre></div>



<script type="text/javascript">
var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-(\w+)\b/i,t=0,n=_self.Prism={util:{encode:function(e){return e instanceof a?new a(e.type,n.util.encode(e.content),e.alias):"Array"===n.util.type(e)?e.map(n.util.encode):e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function(e){var t=n.util.type(e);switch(t){case"Object":var a={};for(var r in e)e.hasOwnProperty(r)&&(a[r]=n.util.clone(e[r]));return a;case"Array":return e.map&&e.map(function(e){return n.util.clone(e)})}return e}},languages:{extend:function(e,t){var a=n.util.clone(n.languages[e]);for(var r in t)a[r]=t[r];return a},insertBefore:function(e,t,a,r){r=r||n.languages;var l=r[e];if(2==arguments.length){a=arguments[1];for(var i in a)a.hasOwnProperty(i)&&(l[i]=a[i]);return l}var o={};for(var s in l)if(l.hasOwnProperty(s)){if(s==t)for(var i in a)a.hasOwnProperty(i)&&(o[i]=a[i]);o[s]=l[s]}return n.languages.DFS(n.languages,function(t,n){n===r[e]&&t!=e&&(this[t]=o)}),r[e]=o},DFS:function(e,t,a,r){r=r||{};for(var l in e)e.hasOwnProperty(l)&&(t.call(e,l,e[l],a||l),"Object"!==n.util.type(e[l])||r[n.util.objId(e[l])]?"Array"!==n.util.type(e[l])||r[n.util.objId(e[l])]||(r[n.util.objId(e[l])]=!0,n.languages.DFS(e[l],t,l,r)):(r[n.util.objId(e[l])]=!0,n.languages.DFS(e[l],t,null,r)))}},plugins:{},highlightAll:function(e,t){var a={callback:t,selector:'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'};n.hooks.run("before-highlightall",a);for(var r,l=a.elements||document.querySelectorAll(a.selector),i=0;r=l[i++];)n.highlightElement(r,e===!0,a.callback)},highlightElement:function(t,a,r){for(var l,i,o=t;o&&!e.test(o.className);)o=o.parentNode;o&&(l=(o.className.match(e)||[,""])[1],i=n.languages[l]),t.className=t.className.replace(e,"").replace(/\s+/g," ")+" language-"+l,o=t.parentNode,/pre/i.test(o.nodeName)&&(o.className=o.className.replace(e,"").replace(/\s+/g," ")+" language-"+l);var s=t.textContent,u={element:t,language:l,grammar:i,code:s};if(!s||!i)return n.hooks.run("complete",u),void 0;if(n.hooks.run("before-highlight",u),a&&_self.Worker){var c=new Worker(n.filename);c.onmessage=function(e){u.highlightedCode=e.data,n.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,r&&r.call(u.element),n.hooks.run("after-highlight",u),n.hooks.run("complete",u)},c.postMessage(JSON.stringify({language:u.language,code:u.code,immediateClose:!0}))}else u.highlightedCode=n.highlight(u.code,u.grammar,u.language),n.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,r&&r.call(t),n.hooks.run("after-highlight",u),n.hooks.run("complete",u)},highlight:function(e,t,r){var l=n.tokenize(e,t);return a.stringify(n.util.encode(l),r)},tokenize:function(e,t){var a=n.Token,r=[e],l=t.rest;if(l){for(var i in l)t[i]=l[i];delete t.rest}e:for(var i in t)if(t.hasOwnProperty(i)&&t[i]){var o=t[i];o="Array"===n.util.type(o)?o:[o];for(var s=0;s<o.length;++s){var u=o[s],c=u.inside,g=!!u.lookbehind,h=!!u.greedy,f=0,d=u.alias;u=u.pattern||u;for(var p=0;p<r.length;p++){var m=r[p];if(r.length>e.length)break e;if(!(m instanceof a)){u.lastIndex=0;var y=u.exec(m),v=1;if(!y&&h&&p!=r.length-1){var b=r[p+1].matchedStr||r[p+1],k=m+b;if(p<r.length-2&&(k+=r[p+2].matchedStr||r[p+2]),u.lastIndex=0,y=u.exec(k),!y)continue;var w=y.index+(g?y[1].length:0);if(w>=m.length)continue;var _=y.index+y[0].length,P=m.length+b.length;if(v=3,P>=_){if(r[p+1].greedy)continue;v=2,k=k.slice(0,P)}m=k}if(y){g&&(f=y[1].length);var w=y.index+f,y=y[0].slice(f),_=w+y.length,S=m.slice(0,w),O=m.slice(_),j=[p,v];S&&j.push(S);var A=new a(i,c?n.tokenize(y,c):y,d,y,h);j.push(A),O&&j.push(O),Array.prototype.splice.apply(r,j)}}}}}return r},hooks:{all:{},add:function(e,t){var a=n.hooks.all;a[e]=a[e]||[],a[e].push(t)},run:function(e,t){var a=n.hooks.all[e];if(a&&a.length)for(var r,l=0;r=a[l++];)r(t)}}},a=n.Token=function(e,t,n,a,r){this.type=e,this.content=t,this.alias=n,this.matchedStr=a||null,this.greedy=!!r};if(a.stringify=function(e,t,r){if("string"==typeof e)return e;if("Array"===n.util.type(e))return e.map(function(n){return a.stringify(n,t,e)}).join("");var l={type:e.type,content:a.stringify(e.content,t,r),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:r};if("comment"==l.type&&(l.attributes.spellcheck="true"),e.alias){var i="Array"===n.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}n.hooks.run("wrap",l);var o="";for(var s in l.attributes)o+=(o?" ":"")+s+'="'+(l.attributes[s]||"")+'"';return"<"+l.tag+' class="'+l.classes.join(" ")+'" '+o+">"+l.content+"</"+l.tag+">"},!_self.document)return _self.addEventListener?(_self.addEventListener("message",function(e){var t=JSON.parse(e.data),a=t.language,r=t.code,l=t.immediateClose;_self.postMessage(n.highlight(r,n.languages[a],a)),l&&_self.close()},!1),_self.Prism):_self.Prism;var r=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return r&&(n.filename=r.src,document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",n.highlightAll)),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
</script>


</body>

</html>
